import thread
from webob.response import Response
from hurryoff.core.router import Router
from hurryoff.core.filters import transferFilter
from hurryoff.services.parsers import getTimeDelta, getTimeDeltaInSeconds, convertSecondsToHoursMinutes
from hurryoff.db import *
import hurryoff.log as log
import simplejson, uuid
import hurryoff.services.trainService as trains
import hurryoff.services.parsers as parsers
from sqlalchemy.exc import IntegrityError
from sqlalchemy.sql.expression import asc

logger = log.module_logger("views")

def main(request):
    return {'uuid' : None}

def findRoutes(fromLocation, toLocation, search_id):
    router = Router(fromLocation, toLocation, filters=[transferFilter])
    session = Session()
    try:
        for route in router.getRoutes():
            totalTime = 0
            for (index, pathPart) in enumerate(route):
                pathPart.trainNumber = session.query(Train).filter(Train.id == pathPart.trainId).one().number
                pathPart.travelTime = "%dh %dm" % getTimeDelta(pathPart.departureTime, pathPart.destinationTime)
                totalTime += getTimeDeltaInSeconds(pathPart.departureTime, pathPart.destinationTime)
                if index:
                    totalTime += getTimeDeltaInSeconds(route[index - 1].destinationTime, route[index].departureTime)
            route[0].total = "%dh %dm" % convertSecondsToHoursMinutes(totalTime)
            jsonObj = parsers.jsonDumpObject(route)
            if not session.query(ResultRecord).filter(ResultRecord.uuid == search_id).filter(ResultRecord.result == jsonObj).count():
                session.add(ResultRecord(search_id, jsonObj))
                session.commit()
        session.add(ResultRecord(search_id, "End."))
        session.commit()
    finally:
        session.close()

@log.functionTracer
def searchPath(model, request):
    search_id = uuid.uuid1()
    thread.start_new_thread(findRoutes, (request.params["from"], request.params["to"], search_id))
    return { 'uuid' : search_id }

def results(model, request):
    session = DBSession()
    return session.query(ResultRecord.result).filter(ResultRecord.uuid == request.params["uuid"]).all()

@log.functionTracer
def stations_json(model, request):
    term = request.params["term"]
    limit = request.params["limit"]
    logger.info("get stations by term '%s'" % term)
    session = DBSession()
    stations = session.query(Station.name)\
                .filter(Station.name.like(u"{0}%".format(term)))\
                .order_by(asc(Station.name))[:limit]
    return [s[0] for s in stations]

@log.functionTracer
def admin(model, request):
    session = DBSession()
    return {'trains' : list(iter(session.query(Train))), 'msg' : None, 'errorMsg' : None }

@log.functionTracer
def adminAction(model, request):
    action_name = request.matchdict["action_name"]
    import admin as adminModule
    if hasattr(adminModule, action_name):
        action = getattr(adminModule, action_name)
        result = action(request)
        if not result:
            return dict(admin(model, request), **{'msg': "Operation %s ends successfully" % action_name})
        else:
            return dict(admin(model, request), **{ 'errorMsg' : result })
    else:
        return dict(admin(model, request), **{ 'errorMsg' : "Operation %s not found" % action_name })

@log.functionTracer
def raw(model, request):
    raw_id = request.matchdict["rawData_id"]
    session = DBSession()
    raw_data = session.query(RawData).filter(RawData.id == raw_id).first()
    if raw_data:
        return Response(raw_data.data)
    return Response("Raw Data with id = %s not found" % raw_id)

@log.functionTracer
def trainAdd(model, request):
    train = simplejson.loads(request.params['train'])
    try:
        trains.addTrain(Train(train['number'], train['name'], list(trains.parseStops(train['stops'])), train['raw_id']))
    except KeyError:
        return Response("Bad train format")
    except IntegrityError as e:
        logger.error(e)
        logger.warn("Train with name = '%s' number = '%s' and already exists" % (train['name'], train['number']))
    return Response("Success")